/**
 * 
 */
package com.cn.practice.decorator;

/**
 * 装饰者模式-类似于快递打包
 * 一个商品可以用报纸包住第一层，用塑料袋包住第二层，用箱子再装起来打包带走
 * 但最终我们需要的只是原来的东西 这些包装物对于东西没有任何影响。但是却保证了运输安全
 * 原对象:需要打包的对象抽象出来，然后在实现的时候再抽象一层增加扩展性
 * 包装类:包装类继承了原对象,并且聚合原对象。这样保证包装对象还是原对象的子类，又能当原对象传进去继续包装
 * @author zhangyang
 *
 */
public class DecoratorPractice {
public static void main(String[] args) {
	/**
	 * 需求实现 快递打包 不同品牌的快递打包价格不一样
	 * 不同的打包材料用来打包价格不一样
	 * 假设我们不同快递之间材料打包价一样 
	 * 问 一个商品 用纸打包一次 布再裹一层 再用纸箱装起来计算总的快递费用
	 * 如果扩展更简单 原对象和包装类都能扩展 而且一旦扩展双方都能用
	 */
	ZTO zto = new ZTO();
	//第一层
	Paper paper = new Paper(zto);
	System.out.println(paper.getName());
	System.out.println(paper.cost());
	//第二层
	Cotton cotton = new Cotton(paper);
	System.out.println(cotton.getName());
	System.out.println(cotton.cost());
	//第三层
	Box box = new Box(cotton);
	System.out.println(box.getName());
	System.out.println(box.cost());
}
}

/**
 * 抽象类-物流
 * @author zhangyang
 *
 */
abstract class Flow{
	String name;
	float price;
	//计算总价的方法
	public abstract float cost();
}

/**
 * 抽象类-快递 是物流的一种
 * @author zhangyang
 *
 */
abstract class Express extends Flow{

	/**
	 * 单纯的快递-花费就是快递价
	 */
	@Override
	public float cost() {
		// TODO Auto-generated method stub
		return this.price;
	}
	
	
}

/**
 * 具体实现类-顺丰快递和中通快递
 * @author zhangyang
 *
 */
class ZTO extends Express{
	public ZTO() {
		this.name="中通快递";
		this.price=10;
	}
}
class SF extends Express{
	public SF() {
		this.name="顺丰快递";
		this.price=15;
	}
}

/**
 * 包装类-实现物流类，并把需要包装的物流聚合进来计算总价
 * @author zhangyang
 *
 */
abstract class DecoratorFlow extends Flow{
	Flow flow;

	public DecoratorFlow(Flow flow) {
		super();
		this.flow = flow;
	}

	/**
	 * 由于是包装 所以就要在原来的花费上面加上当前包装的单价
	 */
	@Override
	public float cost() {
		// TODO Auto-generated method stub
		return this.price+flow.cost();
	}
	
	/**
	 * 查看当前快递包含的名字
	 * @return
	 */
	public String getName() {
		//原产品加上材料
		String res=flow.name +"_"+this.name;
		this.name=res;
		return res;
	}
	
}

class Paper extends DecoratorFlow{

	/**
	 * @param flow
	 */
	public Paper(Flow flow) {
		super(flow);
		this.name="打包纸";
		this.price=1f;
		// TODO Auto-generated constructor stub
	}
	
}
class Cotton extends DecoratorFlow{

	/**
	 * @param flow
	 */
	public Cotton(Flow flow) {
		super(flow);
		// TODO Auto-generated constructor stub
		this.name="打包棉花";
		this.price=3f;
	}
}

class Box extends DecoratorFlow{

	/**
	 * @param flow
	 */
	public Box(Flow flow) {
		super(flow);
		// TODO Auto-generated constructor stub
		this.name="打包纸箱";
		this.price=5f;
	}
}